Read, Clean, Recode, Merge
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# Read, Clean, Recode, Unite
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
## Read files
folder <- "C:/Users/Mihai/Desktop/R Notebooks/notebooks/A.1.3. Drama Exercises Kids"
file <- "A13 Tabel date copii.xlsx"
setwd(folder)
Data <- rio::import(file.path(folder, file),
skip = 1)
## Tidy up data
# Function coalesce rows: colapse when NA, unite with "_" when not NA
coalesce2 <- function(...) {
Reduce(function(x, y) {
i <- which(is.na(x))
j <- which(!is.na(x) & !is.na(y))
x[i] <- y[i]
x[j] <- paste(x[j], y[j], sep = "_")
x},
list(...))
}
colnames(Data) <- coalesce2(Data[2,], Data[3,])
Data <- Data[-c(1:3),]
## Solve duplicate names due to excel double header
# Function to paste a string before column name if it doesnt already start with that string
paste_tocolnames <- function(vec_colnames, string_paste){
ind <- grep(pattern = string_paste, vec_colnames) # ignore column that already has string patterm
vec_colnames[-ind] <- paste0(string_paste, vec_colnames[-ind]) # paste pattern to the rest of them
return(vec_colnames)
}
# PANAS pre 7:26, post 37:56
colnames(Data)[7:26] <- paste_tocolnames(colnames(Data)[7:26], "PANAS pre_")
colnames(Data)[37:56] <- paste_tocolnames(colnames(Data)[37:56], "PANAS post_")
colnames(Data) <- enc2native(colnames(Data)) # fix encoding
## Recode known missing values
# str(Data_psiho, list.len = ncol(Data_psiho))
# str(Data_psiho, list.len = ncol(Data_psiho))
Data <-
Data %>%
replace(. == "/", NA) %>% # missing values are coded "/"
replace(. == "-", NA) %>% # missing values are coded "-"
replace(. == "NA", NA) # missing values are coded "NA"
# Exclude some extra rows and columns & some IDs
Data <- Data[, -c(57:86)]
rownames(Data) <- seq(length=nrow(Data)) # 83 trebuie sa fie
Data <-
Data %>%
mutate (`Nr crt` = as.numeric(.$`Nr crt`)) %>%
filter(!`Nr crt` %in% c(36, 38:39, 41:43, 50:51, 53:55, 75, 84:97)) %>%
filter(`Nr crt` < 84)
## Check for non-numeric elements in data sets
check_numeric1 <- as.data.frame(sapply(Data, varhandle::check.numeric))
# sapply(check_numeric1, function(x) length(which(!x))) # look at columns with non-numeric and count of non-numeric values
nonnumeric1 <- sapply(check_numeric1, function(x) which(!x, arr.ind = TRUE)) # find row numbers for non-numeric values
nonnumeric1[lapply(nonnumeric1, length) > 0] # return only columns and rown numbers were non-numeric
## Recode to numeric
Data[, 7:56] <- sapply(Data[, 7:56], as.numeric) # mutate_at fails due to encoding
## Rename columns
Data <-
Data %>%
dplyr::rename(ID = `Indica tiv subiect`) %>%
dplyr::rename(Zi = `(Etapa III), zi`)
names(Data) <- gsub(" ", "_", names(Data))
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# Scoring Questionnaire and Unite
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
## Define function that calculates RowSums but only for rows with less than 10% NAs; and return NA if all row values are NA
SpecialRowSums <- function(df, napercent = .1) {
ifelse(rowSums(is.na(df)) > ncol(df) * napercent,
NA,
rowSums(df, na.rm = TRUE) * NA ^ (rowSums(!is.na(df)) == 0)
)
}
## PANAS: Positive Affect Score = sum items 1, 3, 5, 9, 10, 12, 14, 16, 17, 19. Negative Affect Score = sum items 2, 4, 6, 7, 8, 11, 13, 15, 18, 20.
Data$PA_pre_Total <- SpecialRowSums(Data[ ,6 + c(1,3,5,9,10,12,14,16,17,19)], napercent = .11) # not more than 1 NAs for 10 items
Data$NA_pre_Total <- SpecialRowSums(Data[ ,6 + c(2,4,6,7,8,11,13,15,18,20)], napercent = .11)
Data$PA_post_Total <- SpecialRowSums(Data[ ,36 + c(1,3,5,9,10,12,14,16,17,19)], napercent = .11)
Data$NA_post_Total <- SpecialRowSums(Data[ ,36 + c(2,4,6,7,8,11,13,15,18,20)], napercent = .11)
Sample descriptives
## Number of subjects
Define Function
## Func t test si boxplot simplu
func_t_box <- function(df, ind, pre_var, post_var){
df_modif <-
df %>%
select(ind, pre_var, post_var) %>%
tidyr::drop_na() %>%
gather(pre_var, post_var, key = "Cond", value = "value") %>%
mutate_at(vars(c(1, 2)), funs(as.factor)) %>%
mutate(Cond = factor(Cond, levels = c(pre_var, post_var)))
stat_comp <- ggpubr::compare_means(value ~ Cond, data = df_modif, method = "t.test", paired = TRUE)
stat_comp2 <-
df_modif %>%
do(tidy(t.test(.$value ~ .$Cond,
paired = TRUE,
data=.)))
plot <-
ggpubr::ggpaired(df_modif, x = "Cond", y = "value", id = ind,
color = "Cond", line.color = "gray", line.size = 0.4,
palette = c("#00AFBB", "#FC4E07"), legend = "none") +
stat_summary(fun.data = mean_se, colour = "darkred") +
ggpubr::stat_compare_means(method = "t.test", paired = TRUE, label.x = as.numeric(df_modif$Cond)-0.4, label.y = max(df_modif$value)+0.5) +
ggpubr::stat_compare_means(method = "t.test", paired = TRUE, label = "p.signif", comparisons = list(c(pre_var, post_var)))
cat(paste0("#### ", pre_var, " ", post_var, "\n", "\n"))
print(stat_comp)
print(stat_comp2)
print(plot)
}
PANAS
Positeive - Zi 1
PA_pre_Total PA_post_Total
Positeive - Zi 2
PA_pre_Total PA_post_Total
Negative - Zi 1
NA_pre_Total NA_post_Total
Negative - Zi 2
NA_pre_Total NA_post_Total
VAS
Stress - Zi 1
VAS_stres_pre VAS_stres_post_ex1
Stress - Zi 2
VAS_stres_pre VAS_stres_post_ex1
Well being - Zi 1
VAS_stare_de_bine_pre VAS_stare_de_bine_post_ex1
Well being - Zi 2
VAS_stare_de_bine_pre VAS_stare_de_bine_post_ex1
IOS
IOS - Zi 1
IOS_pre IOS_post
IOS - Zi 2
IOS_pre IOS_post
Session Info
R version 3.6.1 (2019-07-05)
Platform: x86_64-w64-mingw32/x64 (64-bit)
Running under: Windows 8.1 x64 (build 9600)
Matrix products: default
locale:
[1] LC_COLLATE=Romanian_Romania.1250 LC_CTYPE=Romanian_Romania.1250 LC_MONETARY=Romanian_Romania.1250 LC_NUMERIC=C
[5] LC_TIME=Romanian_Romania.1250
attached base packages:
[1] stats graphics grDevices utils datasets methods base
other attached packages:
[1] rio_0.5.16 scales_1.0.0 ggpubr_0.2 magrittr_1.5 tadaatoolbox_0.16.1
[6] summarytools_0.8.8 rstatix_0.2.0 broom_0.5.2 PerformanceAnalytics_1.5.2 xts_0.11-2
[11] zoo_1.8-4 psych_1.8.12 plyr_1.8.4 forcats_0.4.0 stringr_1.4.0
[16] dplyr_0.8.3 purrr_0.3.2 readr_1.3.1 tidyr_1.0.0 tibble_2.1.3
[21] ggplot2_3.2.1 tidyverse_1.2.1 papaja_0.1.0.9842 pacman_0.5.1
loaded via a namespace (and not attached):
[1] nlme_3.1-140 bitops_1.0-6 matrixStats_0.54.0 lubridate_1.7.4 httr_1.4.0 tools_3.6.1 backports_1.1.4
[8] R6_2.4.0 nortest_1.0-4 lazyeval_0.2.2 colorspace_1.4-1 withr_2.1.2 tidyselect_0.2.5 gridExtra_2.3
[15] mnormt_1.5-5 pixiedust_0.8.6 curl_3.2 compiler_3.6.1 cli_1.1.0 rvest_0.3.2 expm_0.999-3
[22] xml2_1.2.0 labeling_0.3 mvtnorm_1.0-11 quadprog_1.5-5 digest_0.6.21 foreign_0.8-71 pkgconfig_2.0.3
[29] htmltools_0.3.6 pwr_1.2-2 rlang_0.4.0 readxl_1.1.0 rstudioapi_0.8 pryr_0.1.4 generics_0.0.2
[36] jsonlite_1.6 zip_1.0.0 car_3.0-2 RCurl_1.95-4.11 rapportools_1.0 Matrix_1.2-17 Rcpp_1.0.2
[43] DescTools_0.99.29 munsell_0.5.0 abind_1.4-5 viridis_0.5.1 lifecycle_0.1.0 stringi_1.4.3 carData_3.0-2
[50] MASS_7.3-51.4 grid_3.6.1 parallel_3.6.1 crayon_1.3.4 lattice_0.20-38 haven_2.1.1 pander_0.6.3
[57] hms_0.5.1 zeallot_0.1.0 knitr_1.25 pillar_1.4.2 varhandle_2.0.4 boot_1.3-22 ggsignif_0.4.0
[64] codetools_0.2-16 glue_1.3.1 data.table_1.11.8 modelr_0.1.5 vctrs_0.2.0 cellranger_1.1.0 gtable_0.3.0
[71] assertthat_0.2.1 xfun_0.9 openxlsx_4.1.0 viridisLite_0.3.0 ellipsis_0.3.0
A work by Claudiu Papasteri
claudiu.papasteri@gmail.com
LS0tDQp0aXRsZTogIjxicj4gRHJhbWEgRXhlcmNpc2VzIEtpZHMiIA0Kc3VidGl0bGU6ICJSZXBvcnQgZm9yIENoaWxkcmVuIGFuZCBBZG9sZXNjZW50cyINCmF1dGhvcjogIjxicj4gQ2xhdWRpdSBQYXBhc3RlcmkiDQpkYXRlOiAiYHIgZm9ybWF0KFN5cy50aW1lKCksICclZCAlbSAlWScpYCINCm91dHB1dDogDQogICAgaHRtbF9ub3RlYm9vazoNCiAgICAgICAgICAgIGNvZGVfZm9sZGluZzogaGlkZQ0KICAgICAgICAgICAgdG9jOiB0cnVlDQogICAgICAgICAgICB0b2NfZGVwdGg6IDINCiAgICAgICAgICAgIG51bWJlcl9zZWN0aW9uczogdHJ1ZQ0KICAgICAgICAgICAgdGhlbWU6IHNwYWNlbGFiDQogICAgICAgICAgICBoaWdobGlnaHQ6IHRhbmdvDQogICAgICAgICAgICBmb250LWZhbWlseTogQXJpYWwNCiAgICAgICAgICAgIGZpZ193aWR0aDogMTANCiAgICAgICAgICAgIGZpZ19oZWlnaHQ6IDkNCiAgICAjIHBkZl9kb2N1bWVudDogDQogICAgICAgICAgICAjIHRvYzogdHJ1ZQ0KICAgICAgICAgICAgIyAgdG9jX2RlcHRoOiAyDQogICAgICAgICAgICAjICBudW1iZXJfc2VjdGlvbnM6IHRydWUNCiAgICAgICAgICAgICMgZm9udHNpemU6IDExcHQNCiAgICAgICAgICAgICMgZ2VvbWV0cnk6IG1hcmdpbj0xaW4NCiAgICAgICAgICAgICMgZmlnX3dpZHRoOiA3DQogICAgICAgICAgICAjIGZpZ19oZWlnaHQ6IDYNCiAgICAgICAgICAgICMgZmlnX2NhcHRpb246IHRydWUNCiAgICAjIGdpdGh1Yl9kb2N1bWVudDogDQogICAgICAgICAgICAjIHRvYzogdHJ1ZQ0KICAgICAgICAgICAgIyB0b2NfZGVwdGg6IDINCiAgICAgICAgICAgICMgaHRtbF9wcmV2aWV3OiBmYWxzZQ0KICAgICAgICAgICAgIyBmaWdfd2lkdGg6IDUNCiAgICAgICAgICAgICMgZmlnX2hlaWdodDogNQ0KICAgICAgICAgICAgIyBkZXY6IGpwZWcNCi0tLQ0KDQoNCjwhLS0gU2V0dXAgLS0+DQoNCg0KYGBge3Igc2V0dXAsIGluY2x1ZGU9RkFMU0V9DQojIGtpbnRyIG9wdGlvbnMNCmtuaXRyOjpvcHRzX2NodW5rJHNldCgNCiAgY29tbWVudCA9ICIjIiwNCiAgY29sbGFwc2UgPSBUUlVFLA0KICBlY2hvID0gVFJVRSwgd2FybmluZyA9IEZBTFNFLCBtZXNzYWdlID0gVFJVRSwgY2FjaGUgPSBUUlVFICAgICAgICMgZWNobyA9IEZhbHNlIGZvciBnaXRodWJfZG9jdW1lbnQsIGJ1dCB3aWxsIGJlIGZvbGRlZCBpbiBodG1sX25vdGVib29rDQopDQoNCiMgR2VuZXJhbCBSIG9wdGlvbnMgYW5kIGluZm8NCnNldC5zZWVkKDExMSkgICAgICAgICAgICAgICAjIGluIGNhc2Ugd2UgdXNlIHJhbmRvbWl6ZWQgcHJvY2VkdXJlcyAgICAgICANCm9wdGlvbnMoc2NpcGVuID0gOTk5KSAgICAgICAjIHBvc2l0aXZlIHZhbHVlcyBiaWFzIHRvd2FyZHMgZml4ZWQgYW5kIG5lZ2F0aXZlIHRvd2FyZHMgc2NpZW50aWZpYyBub3RhdGlvbg0KDQojIExvYWQgcGFja2FnZXMNCmlmICghcmVxdWlyZSgicGFjbWFuIikpIGluc3RhbGwucGFja2FnZXMoInBhY21hbiIpDQpwYWNrYWdlcyA8LSBjKA0KICAicGFwYWphIiwNCiAgInRpZHl2ZXJzZSIsICJwbHlyIiwgICAgICANCiAgInBzeWNoIiwgIlBlcmZvcm1hbmNlQW5hbHl0aWNzIiwgICAgICAgICAgDQogICJicm9vbSIsICJyc3RhdGl4IiwNCiAgInN1bW1hcnl0b29scyIsICJ0YWRhYXRvb2xib3giLCAgICAgICAgICAgDQogICJnZ3Bsb3QyIiwgImdncHViciIsICJzY2FsZXMiLCAgICAgICAgDQogICJyaW8iDQogICMgLCAuLi4NCikNCmlmICghcmVxdWlyZSgicGFjbWFuIikpIGluc3RhbGwucGFja2FnZXMoInBhY21hbiIpDQpwYWNtYW46OnBfbG9hZChjaGFyID0gcGFja2FnZXMpDQoNCiMgVGhlbWVzIGZvciBnZ3Bsb3QyIHBsb3RpbmcgKGhlcmUgdXNlZCBBUEEgc3R5bGUpDQp0aGVtZV9zZXQodGhlbWVfYXBhKCkpDQpgYGANCg0KDQoNCg0KDQo8IS0tIFJlcG9ydCAtLT4NCg0KDQojIFJlYWQsIENsZWFuLCBSZWNvZGUsIE1lcmdlDQoNCmBgYHtyIHJlZF9jbGVhbl9yZWNvZGVfbWVyZ2UsIHJlc3VsdHM9J2hpZGUnfQ0KI35+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn4NCiMgUmVhZCwgQ2xlYW4sIFJlY29kZSwgVW5pdGUNCiN+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+DQoNCiMjIFJlYWQgZmlsZXMNCmZvbGRlciA8LSAiQzovVXNlcnMvTWloYWkvRGVza3RvcC9SIE5vdGVib29rcy9ub3RlYm9va3MvQS4xLjMuIERyYW1hIEV4ZXJjaXNlcyBLaWRzIg0KZmlsZSA8LSAiQTEzIFRhYmVsIGRhdGUgY29waWkueGxzeCINCg0Kc2V0d2QoZm9sZGVyKQ0KRGF0YSA8LSByaW86OmltcG9ydChmaWxlLnBhdGgoZm9sZGVyLCBmaWxlKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgIHNraXAgPSAxKQ0KDQoNCiMjIFRpZHkgdXAgZGF0YQ0KIyBGdW5jdGlvbiBjb2FsZXNjZSByb3dzOiBjb2xhcHNlIHdoZW4gTkEsIHVuaXRlIHdpdGggIl8iIHdoZW4gbm90IE5BDQpjb2FsZXNjZTIgPC0gZnVuY3Rpb24oLi4uKSB7DQogIFJlZHVjZShmdW5jdGlvbih4LCB5KSB7DQogICAgaSA8LSB3aGljaChpcy5uYSh4KSkNCiAgICBqIDwtIHdoaWNoKCFpcy5uYSh4KSAmICFpcy5uYSh5KSkNCiAgICB4W2ldIDwtIHlbaV0NCiAgICB4W2pdIDwtIHBhc3RlKHhbal0sIHlbal0sIHNlcCA9ICJfIikNCiAgICB4fSwNCiAgICBsaXN0KC4uLikpDQp9DQoNCmNvbG5hbWVzKERhdGEpIDwtIGNvYWxlc2NlMihEYXRhWzIsXSwgRGF0YVszLF0pDQpEYXRhIDwtIERhdGFbLWMoMTozKSxdDQoNCg0KDQojIyBTb2x2ZSBkdXBsaWNhdGUgbmFtZXMgZHVlIHRvIGV4Y2VsIGRvdWJsZSBoZWFkZXINCiMgRnVuY3Rpb24gdG8gcGFzdGUgYSBzdHJpbmcgYmVmb3JlIGNvbHVtbiBuYW1lIGlmIGl0IGRvZXNudCBhbHJlYWR5IHN0YXJ0IHdpdGggdGhhdCBzdHJpbmcNCnBhc3RlX3RvY29sbmFtZXMgPC0gZnVuY3Rpb24odmVjX2NvbG5hbWVzLCBzdHJpbmdfcGFzdGUpew0KICBpbmQgPC0gZ3JlcChwYXR0ZXJuID0gc3RyaW5nX3Bhc3RlLCB2ZWNfY29sbmFtZXMpICAgICAgICAgICAgICAgICAgICMgaWdub3JlIGNvbHVtbiB0aGF0IGFscmVhZHkgaGFzIHN0cmluZyBwYXR0ZXJtDQogIHZlY19jb2xuYW1lc1staW5kXSA8LSBwYXN0ZTAoc3RyaW5nX3Bhc3RlLCB2ZWNfY29sbmFtZXNbLWluZF0pICAgICAgIyBwYXN0ZSBwYXR0ZXJuIHRvIHRoZSByZXN0IG9mIHRoZW0NCiAgcmV0dXJuKHZlY19jb2xuYW1lcykNCn0NCg0KIyBQQU5BUyBwcmUgNzoyNiwgcG9zdCAzNzo1Ng0KY29sbmFtZXMoRGF0YSlbNzoyNl0gPC0gcGFzdGVfdG9jb2xuYW1lcyhjb2xuYW1lcyhEYXRhKVs3OjI2XSwgIlBBTkFTIHByZV8iKQ0KY29sbmFtZXMoRGF0YSlbMzc6NTZdIDwtIHBhc3RlX3RvY29sbmFtZXMoY29sbmFtZXMoRGF0YSlbMzc6NTZdLCAiUEFOQVMgcG9zdF8iKQ0KDQpjb2xuYW1lcyhEYXRhKSA8LSBlbmMybmF0aXZlKGNvbG5hbWVzKERhdGEpKSAgICAgICMgZml4IGVuY29kaW5nDQoNCg0KIyMgUmVjb2RlIGtub3duIG1pc3NpbmcgdmFsdWVzDQojIHN0cihEYXRhX3BzaWhvLCBsaXN0LmxlbiA9IG5jb2woRGF0YV9wc2lobykpDQojIHN0cihEYXRhX3BzaWhvLCBsaXN0LmxlbiA9IG5jb2woRGF0YV9wc2lobykpDQpEYXRhIDwtDQogIERhdGEgJT4lDQogIHJlcGxhY2UoLiA9PSAiLyIsIE5BKSAlPiUgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIyBtaXNzaW5nIHZhbHVlcyBhcmUgY29kZWQgIi8iDQogIHJlcGxhY2UoLiA9PSAiLSIsIE5BKSAlPiUgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIyBtaXNzaW5nIHZhbHVlcyBhcmUgY29kZWQgIi0iDQogIHJlcGxhY2UoLiA9PSAiTkEiLCBOQSkgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIyBtaXNzaW5nIHZhbHVlcyBhcmUgY29kZWQgIk5BIg0KDQoNCiMgRXhjbHVkZSBzb21lIGV4dHJhIHJvd3MgYW5kIGNvbHVtbnMgJiBzb21lIElEcw0KRGF0YSA8LSBEYXRhWywgLWMoNTc6ODYpXQ0Kcm93bmFtZXMoRGF0YSkgPC0gc2VxKGxlbmd0aD1ucm93KERhdGEpKSAgIyA4MyB0cmVidWllIHNhIGZpZQ0KRGF0YSA8LSANCiAgRGF0YSAlPiUNCiAgbXV0YXRlIChgTnIgY3J0YCA9IGFzLm51bWVyaWMoLiRgTnIgY3J0YCkpICU+JQ0KICBmaWx0ZXIoIWBOciBjcnRgICVpbiUgYygzNiwgMzg6MzksIDQxOjQzLCA1MDo1MSwgNTM6NTUsIDc1LCA4NDo5NykpICU+JQ0KICBmaWx0ZXIoYE5yIGNydGAgPCA4NCkNCg0KIyMgQ2hlY2sgZm9yIG5vbi1udW1lcmljIGVsZW1lbnRzIGluIGRhdGEgc2V0cw0KY2hlY2tfbnVtZXJpYzEgPC0gYXMuZGF0YS5mcmFtZShzYXBwbHkoRGF0YSwgdmFyaGFuZGxlOjpjaGVjay5udW1lcmljKSkgDQojIHNhcHBseShjaGVja19udW1lcmljMSwgZnVuY3Rpb24oeCkgbGVuZ3RoKHdoaWNoKCF4KSkpICAgICAjIGxvb2sgYXQgY29sdW1ucyB3aXRoIG5vbi1udW1lcmljIGFuZCBjb3VudCBvZiBub24tbnVtZXJpYyB2YWx1ZXMNCg0Kbm9ubnVtZXJpYzEgPC0gc2FwcGx5KGNoZWNrX251bWVyaWMxLCBmdW5jdGlvbih4KSB3aGljaCgheCwgYXJyLmluZCA9IFRSVUUpKSAgICAjIGZpbmQgcm93IG51bWJlcnMgZm9yIG5vbi1udW1lcmljIHZhbHVlcw0Kbm9ubnVtZXJpYzFbbGFwcGx5KG5vbm51bWVyaWMxLCBsZW5ndGgpID4gMF0gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICMgcmV0dXJuIG9ubHkgY29sdW1ucyBhbmQgcm93biBudW1iZXJzIHdlcmUgbm9uLW51bWVyaWMNCg0KIyMgUmVjb2RlIHRvIG51bWVyaWMNCkRhdGFbLCA3OjU2XSA8LSBzYXBwbHkoRGF0YVssIDc6NTZdLCBhcy5udW1lcmljKSAgICAgIyBtdXRhdGVfYXQgZmFpbHMgZHVlIHRvIGVuY29kaW5nDQoNCiMjIFJlbmFtZSBjb2x1bW5zDQpEYXRhIDwtIA0KICBEYXRhICU+JSANCiBkcGx5cjo6cmVuYW1lKElEID0gYEluZGljYSB0aXYgc3ViaWVjdGApICU+JSANCiBkcGx5cjo6cmVuYW1lKFppID0gYChFdGFwYSBJSUkpLCB6aWApDQpuYW1lcyhEYXRhKSA8LSBnc3ViKCIgIiwgIl8iLCBuYW1lcyhEYXRhKSkNCg0KDQojfn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fg0KIyBTY29yaW5nIFF1ZXN0aW9ubmFpcmUgYW5kIFVuaXRlDQojfn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fg0KIyMgRGVmaW5lIGZ1bmN0aW9uIHRoYXQgY2FsY3VsYXRlcyBSb3dTdW1zIGJ1dCBvbmx5IGZvciByb3dzIHdpdGggbGVzcyB0aGFuIDEwJSBOQXM7IGFuZCByZXR1cm4gTkEgaWYgYWxsIHJvdyB2YWx1ZXMgYXJlIE5BIA0KU3BlY2lhbFJvd1N1bXMgPC0gZnVuY3Rpb24oZGYsIG5hcGVyY2VudCA9IC4xKSB7DQogIGlmZWxzZShyb3dTdW1zKGlzLm5hKGRmKSkgPiBuY29sKGRmKSAqIG5hcGVyY2VudCwNCiAgICAgICAgIE5BLA0KICAgICAgICAgcm93U3VtcyhkZiwgbmEucm0gPSBUUlVFKSAqIE5BIF4gKHJvd1N1bXMoIWlzLm5hKGRmKSkgPT0gMCkNCiAgKQ0KfQ0KDQojIyBQQU5BUzogUG9zaXRpdmUgQWZmZWN0IFNjb3JlID0gc3VtIGl0ZW1zIDEsIDMsIDUsIDksIDEwLCAxMiwgMTQsIDE2LCAxNywgMTkuIE5lZ2F0aXZlIEFmZmVjdCBTY29yZSA9IHN1bSBpdGVtcyAyLCA0LCA2LCA3LCA4LCAxMSwgMTMsIDE1LCAxOCwgMjAuDQpEYXRhJFBBX3ByZV9Ub3RhbCA8LSBTcGVjaWFsUm93U3VtcyhEYXRhWyAsNiArIGMoMSwzLDUsOSwxMCwxMiwxNCwxNiwxNywxOSldLCBuYXBlcmNlbnQgPSAuMTEpICMgbm90IG1vcmUgdGhhbiAxIE5BcyBmb3IgMTAgaXRlbXMNCkRhdGEkTkFfcHJlX1RvdGFsIDwtIFNwZWNpYWxSb3dTdW1zKERhdGFbICw2ICsgYygyLDQsNiw3LDgsMTEsMTMsMTUsMTgsMjApXSwgbmFwZXJjZW50ID0gLjExKQ0KDQoNCkRhdGEkUEFfcG9zdF9Ub3RhbCA8LSBTcGVjaWFsUm93U3VtcyhEYXRhWyAsMzYgKyBjKDEsMyw1LDksMTAsMTIsMTQsMTYsMTcsMTkpXSwgbmFwZXJjZW50ID0gLjExKSANCkRhdGEkTkFfcG9zdF9Ub3RhbCA8LSBTcGVjaWFsUm93U3VtcyhEYXRhWyAsMzYgKyBjKDIsNCw2LDcsOCwxMSwxMywxNSwxOCwyMCldLCBuYXBlcmNlbnQgPSAuMTEpDQpgYGANCg0KDQojIFNhbXBsZSBkZXNjcmlwdGl2ZXMNCg0KYGBge3Igc2FtcGxlX2Rlc2N9DQpjYXQoIiMjIE51bWJlciBvZiBzdWJqZWN0cyIpDQpEYXRhICU+JSANCiBkcGx5cjo6c3VtbWFyaXNlKGNvdW50ID0gZHBseXI6Om5fZGlzdGluY3QoSUQpKQ0KYGBgDQoNCg0KIyBEZWZpbmUgRnVuY3Rpb24NCg0KYGBge3IgZGVmX2Z1bmMsIGhpZGU9VFJVRX0NCiMjIEZ1bmMgdCB0ZXN0IHNpIGJveHBsb3Qgc2ltcGx1DQpmdW5jX3RfYm94IDwtIGZ1bmN0aW9uKGRmLCBpbmQsIHByZV92YXIsIHBvc3RfdmFyKXsNCiAgZGZfbW9kaWYgPC0NCiAgICBkZiAlPiUNCiAgICBzZWxlY3QoaW5kLCBwcmVfdmFyLCBwb3N0X3ZhcikgJT4lIA0KICAgIHRpZHlyOjpkcm9wX25hKCkgJT4lDQogICAgZ2F0aGVyKHByZV92YXIsIHBvc3RfdmFyLCBrZXkgPSAiQ29uZCIsIHZhbHVlID0gInZhbHVlIikgJT4lIA0KICAgIG11dGF0ZV9hdCh2YXJzKGMoMSwgMikpLCBmdW5zKGFzLmZhY3RvcikpICU+JSANCiAgICBtdXRhdGUoQ29uZCA9IGZhY3RvcihDb25kLCBsZXZlbHMgPSBjKHByZV92YXIsIHBvc3RfdmFyKSkpIA0KICANCiAgc3RhdF9jb21wIDwtIGdncHVicjo6Y29tcGFyZV9tZWFucyh2YWx1ZSB+IENvbmQsIGRhdGEgPSBkZl9tb2RpZiwgbWV0aG9kID0gInQudGVzdCIsIHBhaXJlZCA9IFRSVUUpDQogIA0KICBzdGF0X2NvbXAyIDwtDQogICAgZGZfbW9kaWYgJT4lIA0KICAgIGRvKHRpZHkodC50ZXN0KC4kdmFsdWUgfiAuJENvbmQsDQogICAgICAgICAgICAgICAgICAgcGFpcmVkID0gVFJVRSwNCiAgICAgICAgICAgICAgICAgICBkYXRhPS4pKSkNCiAgDQogIHBsb3QgPC0gDQogICAgZ2dwdWJyOjpnZ3BhaXJlZChkZl9tb2RpZiwgeCA9ICJDb25kIiwgeSA9ICJ2YWx1ZSIsIGlkID0gaW5kLCANCiAgICAgICAgICAgICAgICAgICAgIGNvbG9yID0gIkNvbmQiLCBsaW5lLmNvbG9yID0gImdyYXkiLCBsaW5lLnNpemUgPSAwLjQsDQogICAgICAgICAgICAgICAgICAgICBwYWxldHRlID0gYygiIzAwQUZCQiIsICIjRkM0RTA3IiksIGxlZ2VuZCA9ICJub25lIikgKw0KICAgICAgc3RhdF9zdW1tYXJ5KGZ1bi5kYXRhID0gbWVhbl9zZSwgIGNvbG91ciA9ICJkYXJrcmVkIikgKw0KICAgICAgZ2dwdWJyOjpzdGF0X2NvbXBhcmVfbWVhbnMobWV0aG9kID0gInQudGVzdCIsIHBhaXJlZCA9IFRSVUUsIGxhYmVsLnggPSBhcy5udW1lcmljKGRmX21vZGlmJENvbmQpLTAuNCwgbGFiZWwueSA9IG1heChkZl9tb2RpZiR2YWx1ZSkrMC41KSArIA0KICAgICAgZ2dwdWJyOjpzdGF0X2NvbXBhcmVfbWVhbnMobWV0aG9kID0gInQudGVzdCIsIHBhaXJlZCA9IFRSVUUsIGxhYmVsID0gInAuc2lnbmlmIiwgY29tcGFyaXNvbnMgPSBsaXN0KGMocHJlX3ZhciwgcG9zdF92YXIpKSkNCiAgDQogIGNhdChwYXN0ZTAoIiMjIyMgIiwgcHJlX3ZhciwgIiAiLCBwb3N0X3ZhciwgIlxuIiwgIlxuIikpDQogIHByaW50KHN0YXRfY29tcCkNCiAgcHJpbnQoc3RhdF9jb21wMikNCiAgcHJpbnQocGxvdCkNCn0NCmBgYA0KDQoNCg0KIyBQQU5BUyANCg0KYGBge3IgdF90ZXN0X3BhbmFzLCBmaWcud2lkdGg9NSwgZmlnLmhlaWdodD03LCByZXN1bHRzPSdhc2lzJ30NCmNhdCgiIyMjIFBvc2l0ZWl2ZSAtIFppIDEiKQ0KRGF0YSAlPiUNCiAgZmlsdGVyKFppID09IDEpICU+JQ0KICBmdW5jX3RfYm94KCJJRCIsICJQQV9wcmVfVG90YWwiLCAiUEFfcG9zdF9Ub3RhbCIpDQoNCmNhdCgiIyMjIFBvc2l0ZWl2ZSAtICBaaSAyIikNCkRhdGEgJT4lDQogIGZpbHRlcihaaSA9PSAyKSAlPiUNCiAgZnVuY190X2JveCgiSUQiLCAiUEFfcHJlX1RvdGFsIiwgIlBBX3Bvc3RfVG90YWwiKQ0KDQoNCmNhdCgiIyMjIE5lZ2F0aXZlIC0gWmkgMSIpDQpEYXRhICU+JQ0KICBmaWx0ZXIoWmkgPT0gMSkgJT4lDQogIGZ1bmNfdF9ib3goIklEIiwgIk5BX3ByZV9Ub3RhbCIsICJOQV9wb3N0X1RvdGFsIikNCg0KY2F0KCIjIyMgTmVnYXRpdmUgLSAgWmkgMiIpDQpEYXRhICU+JQ0KICBmaWx0ZXIoWmkgPT0gMikgJT4lDQogIGZ1bmNfdF9ib3goIklEIiwgIk5BX3ByZV9Ub3RhbCIsICJOQV9wb3N0X1RvdGFsIikNCmBgYA0KDQoNCiMgVkFTIA0KDQpgYGB7ciB0X3Rlc3RfdmFzLCBmaWcud2lkdGg9NSwgZmlnLmhlaWdodD03LCByZXN1bHRzPSdhc2lzJ30NCmNhdCgiIyMjIFN0cmVzcyAtIFppIDEiKQ0KRGF0YSAlPiUNCiAgZmlsdGVyKFppID09IDEpICU+JQ0KICBmdW5jX3RfYm94KCJJRCIsICJWQVNfc3RyZXNfcHJlIiwgIlZBU19zdHJlc19wb3N0X2V4MSIpDQoNCmNhdCgiIyMjIFN0cmVzcyAtICBaaSAyIikNCkRhdGEgJT4lDQogIGZpbHRlcihaaSA9PSAyKSAlPiUNCiAgZnVuY190X2JveCgiSUQiLCAiVkFTX3N0cmVzX3ByZSIsICJWQVNfc3RyZXNfcG9zdF9leDEiKQ0KDQoNCmNhdCgiIyMjIFdlbGwgYmVpbmcgLSBaaSAxIikNCkRhdGEgJT4lDQogIGZpbHRlcihaaSA9PSAxKSAlPiUNCiAgZnVuY190X2JveCgiSUQiLCAiVkFTX3N0YXJlX2RlX2JpbmVfcHJlIiwgIlZBU19zdGFyZV9kZV9iaW5lX3Bvc3RfZXgxIikNCg0KY2F0KCIjIyMgV2VsbCBiZWluZyAtICBaaSAyIikNCkRhdGEgJT4lDQogIGZpbHRlcihaaSA9PSAyKSAlPiUNCiAgZnVuY190X2JveCgiSUQiLCAiVkFTX3N0YXJlX2RlX2JpbmVfcHJlIiwgIlZBU19zdGFyZV9kZV9iaW5lX3Bvc3RfZXgxIikNCmBgYA0KDQoNCiMgSU9TDQoNCmBgYHtyIHRfdGVzdF9pb3MsIGZpZy53aWR0aD01LCBmaWcuaGVpZ2h0PTcsIHJlc3VsdHM9J2FzaXMnfQ0KY2F0KCIjIyMgSU9TIC0gWmkgMSIpDQpEYXRhICU+JQ0KICBmaWx0ZXIoWmkgPT0gMSkgJT4lDQogIGZ1bmNfdF9ib3goIklEIiwgIklPU19wcmUiLCAiSU9TX3Bvc3QiKQ0KDQpjYXQoIiMjIyBJT1MgLSAgWmkgMiIpDQpEYXRhICU+JQ0KICBmaWx0ZXIoWmkgPT0gMikgJT4lDQogIGZ1bmNfdF9ib3goIklEIiwgIklPU19wcmUiLCAiSU9TX3Bvc3QiKQ0KYGBgDQoNCg0KDQoNCjwhLS0gU2Vzc2lvbiBJbmZvIGFuZCBMaWNlbnNlIC0tPg0KDQo8YnI+DQoNCiMgU2Vzc2lvbiBJbmZvDQpgYGB7ciBzZXNzaW9uX2luZm8sIGVjaG8gPSBGQUxTRSwgcmVzdWx0cyA9ICdtYXJrdXAnfQ0Kc2Vzc2lvbkluZm8oKSAgICANCmBgYA0KDQo8IS0tIEZvb3RlciAtLT4NCiZuYnNwOw0KPGhyIC8+DQo8cCBzdHlsZT0idGV4dC1hbGlnbjogY2VudGVyOyI+QSB3b3JrIGJ5IDxhIGhyZWY9Imh0dHBzOi8vZ2l0aHViLmNvbS9DbGF1ZGl1UGFwYXN0ZXJpLyI+Q2xhdWRpdSBQYXBhc3Rlcmk8L2E+PC9wPg0KPHAgc3R5bGU9InRleHQtYWxpZ246IGNlbnRlcjsiPjxzcGFuIHN0eWxlPSJjb2xvcjogIzgwODA4MDsiPjxlbT5jbGF1ZGl1LnBhcGFzdGVyaUBnbWFpbC5jb208L2VtPjwvc3Bhbj48L3A+DQombmJzcDsNCg==